package com.database.dao.impl;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.database.bean.BaseBean;
import com.database.dao.BaseDao;
import com.database.util.AuditInterceptor;

public class BaseDaoImpl<B extends BaseBean> implements BaseDao<B>, Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	protected Logger logger = LoggerFactory.getLogger(getClass());
	private Class<B> queryClass;
	
	@Autowired
	private SessionFactory sessionFactory;
	
	private Session session = null;


	public Session getSession() {
		//session = sessionFactory.withOptions().interceptor(new AuditInterceptor()).openSession();
		if(this.session==null || !session.isOpen()){
			this.session = sessionFactory.withOptions().interceptor(new AuditInterceptor()).openSession();
		}

		return this.session;
	}
	
	public void closeSession(){
		if (this.session != null) {
			//this.session.flush();
			this.session.close();
			this.session=null;
		}
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		logger.debug("Set Autowired SessionFactory: {}",sessionFactory);
		this.sessionFactory = sessionFactory;
	}
	
	/**
	 * @param queryClass
	 */
	public BaseDaoImpl(Class<B> queryClass) {
		super();
		this.queryClass = queryClass;
	}

	@SuppressWarnings("unchecked")
	@Override
	public B getById(Integer id) {
		Transaction tx=null;
		B b=null;
		try{
		session = getSession();
		tx=session.beginTransaction();
		b = (B) session.get(this.getQueryClass(), id);
		tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		
		return b;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public B getById(Integer id, BaseBean bb) {
		Transaction tx=null;
		B b=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			b = (B) session.get(bb.getClass(), id);
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		
		return b;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<B> getAll() {
		logger.info("get all");
		Transaction tx=null;
		List<B> beans=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			beans = session.createQuery(
					"from " + this.getQueryClass().getSimpleName()).list();
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return beans;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<B> getAllActive() {
		logger.info("get all");
		Transaction tx=null;
		List<B> beans=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			beans = session.createQuery(
					"from " + this.getQueryClass().getSimpleName() + " where active=true").list();
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return beans;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<B> getAll(BaseBean bb) {
		logger.info("get all");
		Transaction tx=null;
		List<B> beans=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			beans = session.createQuery(
					"from " + bb.getClass().getSimpleName()).list();
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return beans;
	}

	@Override
	public int create(BaseBean b) {
		logger.debug("Save Basebean: {}",b);
		Transaction tx=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			session.save(b);
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return 0;
	}
	
	@Override
	public BaseBean refresh(BaseBean b) {
		logger.debug("refresh Basebean: {}",b);
		return this.getById(b.getId(),b);
	}

	@Override
	public int update(BaseBean b) {
		Transaction tx=null;
		try{
			this.session = getSession();
			tx=session.beginTransaction();
			session.saveOrUpdate(b);
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return 0;
	}

	@Override
	public int delete(BaseBean b) {
		Transaction tx=null;
		try{
			session = getSession();
			tx=session.beginTransaction();
			session.delete(b);
			tx.commit();
		}catch(Throwable t){
			throw t;
		}
		finally{
			try{
				if(tx!=null){
					tx.rollback();
				}
			}catch(Throwable te){}
			finally{
				if(this.session!=null){
					closeSession();
				}
			}
		}
		return 0;
	}

	/**
	 * @return the queryClass
	 */
	public Class<B> getQueryClass() {
		return queryClass;
	}

	/**
	 * @param queryClass
	 *            the queryClass to set
	 */
	public void setQueryClass(Class<B> queryClass) {
		this.queryClass = queryClass;
	}

}
